package learning.crf.training;

import learning.crf.inference.IParseScorer;
import learning.crf.inference.Parse;
import learning.crf.inference.Viterbi;
import learning.data.document.SequenceDocument;
import learning.util.SparseVector;

public class CRF {

	public static DecodingResult decode(SequenceDocument doc,
			IParseScorer parseScorer, CRFParameters params) {
		
		parseScorer.setDocument(doc);
		parseScorer.setParameters(params);
		
		Viterbi parser = new Viterbi(params.model, parseScorer);
		
		Parse parse = parser.parse(doc.tokens.length);
		
		return new DecodingResult(parse.states, parse.score);
	}
	
	public static void update(SequenceDocument doc, IParseScorer scorer,
			DecodingResult predictedParse, DecodingResult trueParse,  
			CRFParameters iterParameters, float delta) {
		int[] predictedLabel = predictedParse.labels;
		int[] trueLabel = trueParse.labels;
		
		for (int i=0; i < predictedLabel.length; i++) {
			
			if (predictedLabel[i] != trueLabel[i]) {

				//DebugInfo.print(doc, predictedParse, trueParse);
				
				int trueFrom = i > 0 ? trueLabel[i-1] : iterParameters.model.START_STATE;
				int falseFrom = i > 0 ? predictedLabel[i-1] : iterParameters.model.START_STATE;
				
				int trueTo = trueLabel[i];
				int falseTo = predictedLabel[i];
				
				SparseVector v1 = scorer.getFeatures(i, trueFrom, trueTo);
				iterParameters.transitionParameters[trueFrom][trueTo].sum(v1, delta);
				
				SparseVector v2 = scorer.getFeatures(i, falseFrom, falseTo);
				iterParameters.transitionParameters[falseFrom][falseTo].sum(v2, -delta);				
			}
		}
	}

	public static class DecodingResult {
		public int[] labels;
		public float score;
		
		public DecodingResult(int[] labels, float score) {
			this.labels = labels;
			this.score = score;
		}
	}
}
